#!/usr/bin/env python3
"""
5_generate_score.py
综合评分和投资建议生成程序（健壮版）
"""

import pandas as pd
import numpy as np
import sys
import os
from datetime import datetime

class InvestmentScorer:
    def __init__(self):
        self.weights = {
            'technical': 0.25,
            'risk': 0.20,
            'valuation': 0.30,
            'momentum': 0.15,
            'market_condition': 0.10
        }
    
    # ========= 技术指标评分 =========
    def calculate_technical_score(self, df):
        """计算技术指标得分"""
        try:
            rsi = df['rsi14'].iloc[-1]
        except KeyError:
            rsi = np.nan
        if pd.isna(rsi):
            rsi_score = 12.5
        elif rsi < 30:
            rsi_score = 25
        elif rsi > 70:
            rsi_score = 5
        else:
            rsi_score = 15 + (50 - abs(rsi - 50)) / 2
        
        try:
            macd = df['macd'].iloc[-1]
            macd_signal = df['macd_signal'].iloc[-1]
        except KeyError:
            macd = macd_signal = np.nan
        if pd.isna(macd) or pd.isna(macd_signal):
            macd_score = 12.5
        elif macd > 0 and macd > macd_signal:
            macd_score = 25
        elif macd < 0 and macd < macd_signal:
            macd_score = 10
        else:
            macd_score = 15
        
        try:
            ma5 = df['ma5'].iloc[-1]
            ma20 = df['ma20'].iloc[-1]
            ma60 = df['ma60'].iloc[-1]
        except KeyError:
            ma5 = ma20 = ma60 = np.nan
        if pd.isna(ma5) or pd.isna(ma20) or pd.isna(ma60):
            ma_score = 12.5
        else:
            if ma5 > ma20 > ma60:
                ma_score = 25
            elif ma5 < ma20 < ma60:
                ma_score = 5
            else:
                ma_score = 15
        
        try:
            close = df['close'].iloc[-1]
            upper = df['boll_upper'].iloc[-1]
            lower = df['boll_lower'].iloc[-1]
        except KeyError:
            upper = lower = np.nan
            close = np.nan
        if pd.isna(upper) or pd.isna(lower):
            bb_score = 12.5
        else:
            bb_position = (close - lower) / (upper - lower) * 100 if (upper - lower) != 0 else 50
            if bb_position < 20:
                bb_score = 25
            elif bb_position > 80:
                bb_score = 5
            else:
                bb_score = 15
        
        return min(100, max(0, rsi_score + macd_score + ma_score + bb_score))
    
    # ========= 风险评分 =========
    def calculate_risk_score(self, df):
        """计算风险得分（风险越低得分越高）"""
        vol = df['volatility_20d'].iloc[-1] if 'volatility_20d' in df.columns else np.nan
        if pd.isna(vol):
            vol_score = 20
        elif vol < 0.1:
            vol_score = 40
        elif vol < 0.2:
            vol_score = 30
        elif vol < 0.3:
            vol_score = 20
        else:
            vol_score = 10
        
        max_dd = df['max_drawdown_total'].iloc[-1] if 'max_drawdown_total' in df.columns else np.nan
        if pd.isna(max_dd):
            dd_score = 15
        elif abs(max_dd) < 0.1:
            dd_score = 30
        elif abs(max_dd) < 0.2:
            dd_score = 20
        elif abs(max_dd) < 0.3:
            dd_score = 10
        else:
            dd_score = 5
        
        sharpe = df['sharpe_ratio'].iloc[-1] if 'sharpe_ratio' in df.columns else np.nan
        if pd.isna(sharpe):
            sharpe_score = 15
        elif sharpe > 2:
            sharpe_score = 30
        elif sharpe > 1:
            sharpe_score = 20
        elif sharpe > 0:
            sharpe_score = 10
        else:
            sharpe_score = 5
        
        return min(100, max(0, vol_score + dd_score + sharpe_score))
    
    # ========= 估值得分 =========
    def calculate_valuation_score(self, df):
        """计算估值得分"""
        percentile = df['price_percentile'].iloc[-1] if 'price_percentile' in df.columns else np.nan
        if pd.isna(percentile):
            percentile_score = 25
        else:
            percentile_score = max(0, 100 - percentile)
        
        valuation_status = df['valuation_status'].iloc[-1] if 'valuation_status' in df.columns else '合理'
        if valuation_status == '低估':
            status_score = 30
        elif valuation_status == '合理':
            status_score = 20
        elif valuation_status == '高估':
            status_score = 10
        else:
            status_score = 15
        
        distance = abs(df['distance_ma20'].iloc[-1]) if 'distance_ma20' in df.columns else np.nan
        if pd.isna(distance):
            distance_score = 10
        else:
            distance_score = max(0, 100 - distance * 2)
        
        return min(100, max(0, percentile_score + status_score + distance_score))
    
    # ========= 动量得分 =========
    def calculate_momentum_score(self, df):
        """计算动量得分"""
        momentum_20 = df['momentum_20d'].iloc[-1] if 'momentum_20d' in df.columns else np.nan
        if pd.isna(momentum_20):
            momentum_20_score = 25
        elif momentum_20 > 10:
            momentum_20_score = 50
        elif momentum_20 > 0:
            momentum_20_score = 30 + momentum_20 * 2
        elif momentum_20 > -10:
            momentum_20_score = 20 + abs(momentum_20)
        else:
            momentum_20_score = 10
        
        momentum_60 = df['momentum_60d'].iloc[-1] if 'momentum_60d' in df.columns else np.nan
        if pd.isna(momentum_60):
            momentum_60_score = 15
        elif momentum_60 > 20:
            momentum_60_score = 30
        elif momentum_60 > 0:
            momentum_60_score = 15 + momentum_60
        else:
            momentum_60_score = max(0, 15 + momentum_60 * 0.5)
        
        trend_strength = df['trend_strength_20d'].iloc[-1] if 'trend_strength_20d' in df.columns else np.nan
        if pd.isna(trend_strength):
            trend_score = 10
        else:
            trend_score = min(20, abs(trend_strength))
        
        return min(100, max(0, momentum_20_score + momentum_60_score + trend_score))
    
    # ========= 市场环境得分 =========
    def calculate_market_condition_score(self, df):
        """计算市场环境得分"""
        seasonality = df['seasonality_score'].iloc[-1] if 'seasonality_score' in df.columns else np.nan
        if pd.isna(seasonality):
            seasonality_score = 25
        else:
            seasonality_score = 25 + seasonality
        
        volatility_percentile = df['volatility_percentile'].iloc[-1] if 'volatility_percentile' in df.columns else np.nan
        if pd.isna(volatility_percentile):
            vol_score = 15
        else:
            vol_score = max(0, 100 - volatility_percentile * 0.8)
        
        position = df['position_in_range'].iloc[-1] if 'position_in_range' in df.columns else np.nan
        if pd.isna(position):
            position_score = 10
        else:
            if position < 30:
                position_score = 20
            elif position > 70:
                position_score = 5
            else:
                position_score = 15
        
        return min(100, max(0, seasonality_score + vol_score + position_score))
    
    # ========= 投资建议 =========
    def get_recommendation(self, final_score):
        if final_score >= 85:
            return "强烈推荐", "★★★★★"
        elif final_score >= 70:
            return "推荐", "★★★★"
        elif final_score >= 55:
            return "中性", "★★★"
        elif final_score >= 40:
            return "谨慎", "★★"
        else:
            return "回避", "★"
    
    # ========= 目标价与止损 =========
    def calculate_target_prices(self, df):
        current_price = df['close'].iloc[-1]
        
        resistance = df['resistance_level'].iloc[-1] if 'resistance_level' in df.columns else np.nan
        support = df['support_level'].iloc[-1] if 'support_level' in df.columns else np.nan
        
        if pd.isna(resistance) or pd.isna(support):
            fib_618 = df['fib_61.8'].iloc[-1] if 'fib_61.8' in df.columns else np.nan
            fib_382 = df['fib_38.2'].iloc[-1] if 'fib_38.2' in df.columns else np.nan
            
            if not pd.isna(fib_618) and not pd.isna(fib_382):
                target_price = fib_618
                stop_loss = fib_382
            else:
                target_price = current_price * 1.15
                stop_loss = current_price * 0.9
        else:
            target_price = resistance * 1.05
            stop_loss = support * 0.95
        
        return target_price, stop_loss
    
    # ========= 风险等级 =========
    def generate_risk_level(self, df):
        volatility = df['volatility_20d'].iloc[-1] if 'volatility_20d' in df.columns else 0.2
        max_dd = abs(df['max_drawdown_total'].iloc[-1]) if 'max_drawdown_total' in df.columns else 0.2
        
        if volatility < 0.15 and max_dd < 0.1:
            return "低风险"
        elif volatility < 0.25 and max_dd < 0.2:
            return "中低风险"
        elif volatility < 0.35 and max_dd < 0.3:
            return "中高风险"
        else:
            return "高风险"
    
    # ========= 报告生成 =========
    def generate_report(self):
        input_file = '../csv_output/level4_valuation.csv'
        if not os.path.exists(input_file):
            print("❌ level4_valuation.csv 不存在", file=sys.stderr)
            sys.exit(1)
        
        df = pd.read_csv(input_file)
        
        technical_score = self.calculate_technical_score(df)
        risk_score = self.calculate_risk_score(df)
        valuation_score = self.calculate_valuation_score(df)
        momentum_score = self.calculate_momentum_score(df)
        market_score = self.calculate_market_condition_score(df)
        
        final_score = (
            technical_score * self.weights['technical'] +
            risk_score * self.weights['risk'] +
            valuation_score * self.weights['valuation'] +
            momentum_score * self.weights['momentum'] +
            market_score * self.weights['market_condition']
        )
        
        recommendation, stars = self.get_recommendation(final_score)
        
        target_price, stop_loss = self.calculate_target_prices(df)
        risk_level = self.generate_risk_level(df)
        current_price = df['close'].iloc[-1]
        
        result = pd.DataFrame({
            'date': [datetime.now().strftime('%Y-%m-%d')],
            'technical_score': [round(technical_score, 1)],
            'risk_score': [round(risk_score, 1)],
            'valuation_score': [round(valuation_score, 1)],
            'momentum_score': [round(momentum_score, 1)],
            'market_condition_score': [round(market_score, 1)],
            'final_score': [round(final_score, 1)],
            'recommendation': [recommendation],
            'stars': [stars],
            'target_price': [round(target_price, 4)],
            'stop_loss': [round(stop_loss, 4)],
            'risk_level': [risk_level],
            'current_price': [round(current_price, 4)],
            'upside_potential': [round((target_price - current_price) / current_price * 100, 2)],
            'downside_risk': [round((current_price - stop_loss) / current_price * 100, 2)]
        })
        
        result.to_csv('../csv_output/level5_final_score.csv', index=False)
        
        print("=" * 60)
        print("📊 最终分析报告")
        print("=" * 60)
        print(f"🎯 综合评分: {final_score:.1f}/100 {stars}")
        print(f"📈 投资建议: {recommendation}")
        print(f"💰 当前价格: {current_price:.4f}")
        print(f"🚀 目标价格: {target_price:.4f}")
        print(f"📉 止损价格: {stop_loss:.4f}")
        print(f"📊 上涨空间: {(target_price - current_price) / current_price * 100:.2f}%")
        print(f"⚠️  下跌风险: {(current_price - stop_loss) / current_price * 100:.2f}%")
        print(f"🔍 风险等级: {risk_level}")
        print("=" * 60)
        print("📋 分项得分:")
        print(f"  技术指标: {technical_score:.1f}/100")
        print(f"  风险指标: {risk_score:.1f}/100")
        print(f"  估值指标: {valuation_score:.1f}/100")
        print(f"  动量指标: {momentum_score:.1f}/100")
        print(f"  市场环境: {market_score:.1f}/100")

def main():
    if not os.path.exists('../csv_output/level4_valuation.csv'):
        print("❌ 请先运行4_calculate_valuation.py", file=sys.stderr)
        sys.exit(1)
    
    scorer = InvestmentScorer()
    scorer.generate_report()
    print("✅ level5_final_score.csv 已生成")

if __name__ == "__main__":
    main()

